package tournoi.modele;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

@Entity
public class Rencontre implements Serializable {

	public enum InfoSupplementaire {
		TIR_AU_BUT, PROLONGATION, NONE
	};

	/**
	 * 
	 */
	private static final long serialVersionUID = 486140801136425360L;

	private Integer idRencontre;
	private Integer tournoi;
	private Equipe equipeUne;
	private Equipe equipeDeux;
	private List<But> butEquipeUne;
	private List<But> butEquipeDeux;
	private List<But> tirsAuButEquipeUne;
	private List<But> tirsAuButEquipeDeux;
	private Arbitre arbitre;
	private InfoSupplementaire info;
	private Boolean termine;

	public Rencontre() {
		butEquipeUne = new ArrayList<But>();
		butEquipeDeux = new ArrayList<But>();
		tirsAuButEquipeUne = new ArrayList<But>();
		tirsAuButEquipeDeux = new ArrayList<But>();
		info = InfoSupplementaire.NONE;
		termine = false;
	}

	@Id
	@GeneratedValue
	public Integer getIdRencontre() {
		return idRencontre;
	}

	public void setIdRencontre(Integer idRencontre) {
		this.idRencontre = idRencontre;
	}

	public Integer getTournoi() {
		return tournoi;
	}

	public void setTournoi(Integer tournoi) {
		this.tournoi = tournoi;
	}

	@ManyToOne
	public Equipe getEquipeUne() {
		return equipeUne;
	}

	public void setEquipeUne(Equipe equipeUne) {
		this.equipeUne = equipeUne;
	}

	@ManyToOne
	public Equipe getEquipeDeux() {
		return equipeDeux;
	}

	public void setEquipeDeux(Equipe equipeDeux) {
		this.equipeDeux = equipeDeux;
	}

	public Boolean getTermine() {
		return termine;
	}

	public void setTermine(Boolean termine) {
		this.termine = termine;
	}

	@OneToMany(targetEntity = But.class, cascade = { CascadeType.ALL })
	@JoinTable(name = "RENCONTRE_BUT_UNE")
	public List<But> getButEquipeUne() {
		return butEquipeUne;
	}

	public void setButEquipeUne(List<But> butEquipeUne) {
		this.butEquipeUne = butEquipeUne;
	}

	@OneToMany(targetEntity = But.class, cascade = { CascadeType.ALL })
	@JoinTable(name = "RENCONTRE_BUT_DEUX")
	public List<But> getButEquipeDeux() {
		return butEquipeDeux;
	}

	public void setButEquipeDeux(List<But> butEquipeDeux) {
		this.butEquipeDeux = butEquipeDeux;
	}

	public void setTirsAuButEquipeUne(List<But> tirsAuButEquipeUne) {
		this.tirsAuButEquipeUne = tirsAuButEquipeUne;
	}

	@OneToMany(targetEntity = But.class, cascade = { CascadeType.ALL })
	@JoinTable(name = "RENCONTRE_TIRSAUBUT_UNE")
	public List<But> getTirsAuButEquipeUne() {
		return tirsAuButEquipeUne;
	}

	public void setTirsAuButEquipeDeux(List<But> tirsAuButEquipeDeux) {
		this.tirsAuButEquipeDeux = tirsAuButEquipeDeux;
	}

	@OneToMany(targetEntity = But.class, cascade = { CascadeType.ALL })
	@JoinTable(name = "RENCONTRE_TIRSAUBUT_DEUX")
	public List<But> getTirsAuButEquipeDeux() {
		return tirsAuButEquipeDeux;
	}

	@ManyToOne
	public Arbitre getArbitre() {
		return arbitre;
	}

	public void setArbitre(Arbitre arbitre) {
		this.arbitre = arbitre;
	}

	public InfoSupplementaire getInfo() {
		return info;
	}

	public void setInfo(InfoSupplementaire info) {
		this.info = info;
	}

	/*
	 * Méthode pour le tournoi
	 */
	public String nomEquipeUne() {
		return (equipeUne != null) ? equipeUne.getNomEquipe() : "-----";
	}

	public String nomEquipeDeux() {
		return (equipeDeux != null) ? equipeDeux.getNomEquipe() : "-----";
	}

	/**
	 * Renvoie les buts de l'équipe 1 sous formats affichables (en comptant les
	 * tirs au but)
	 * 
	 * @return nombre de buts de l'equipe 1
	 */
	public String butEquipeUne() {
		int but = (butEquipeUne != null) ? butEquipeUne.size() : 0;
		String score = "" + but;
		if (info == InfoSupplementaire.TIR_AU_BUT) {
			int tab = tirsAuButEquipeUne.size();
			score = (but + tab) + " (+" + tab + ")";
		}
		return score;
	}

	/**
	 * Renvoie les buts de l'équipe 2 sous formats affichables (en comptant les
	 * tirs au but)
	 * 
	 * @return nombre de buts de l'equipe 2
	 */
	public String butEquipeDeux() {
		int but = (butEquipeDeux != null) ? butEquipeDeux.size() : 0;
		String score = "" + but;
		if (info == InfoSupplementaire.TIR_AU_BUT) {
			int tab = tirsAuButEquipeDeux.size();
			score = (but + tab) + " (+" + tab + ")";
		}
		return score;
	}

	/**
	 * Récupérer le gagnant de la rencontre
	 * 
	 * @return Equipe gagnante
	 */
	public Equipe gagnant() {
		if (info == InfoSupplementaire.TIR_AU_BUT) {
			if (tirsAuButEquipeUne.size() > tirsAuButEquipeDeux.size()) {
				return equipeUne;
			} else
				return equipeDeux;
		} else {
			if (butEquipeUne.size() > butEquipeDeux.size()) {
				return equipeUne;
			} else
				return equipeDeux;
		}
	}

	/**
	 * Termine le match, jete une exception si les conditions sont mauvais (nul)
	 * 
	 * @throws Exception
	 */
	public void finir() throws Exception {
		if (butEquipeUne.size() != butEquipeDeux.size()
				|| tirsAuButEquipeUne.size() != tirsAuButEquipeDeux.size()) {
			termine = true;
		} else
			throw new Exception("Impossible de finir sur un nul");
	}

	/**
	 * Ajout un but avec l'heure et la personne pour un equipe, jete un
	 * exception détaillée si le but ne peut être ajouté
	 * 
	 * @param equipe
	 * @param nom
	 * @param minute
	 * @throws Exception
	 */
	public void ajouterBut(int equipe, String nom, int minute) throws Exception {
		if (arbitre == null)
			throw new Exception("Pas d'arbitre, pas de but !");

		if (!termine) {
			/* TEST DES MINUTES/PERIODES */
			if ((info == InfoSupplementaire.NONE && minute <= 95)
					|| (info == InfoSupplementaire.PROLONGATION && minute >= 90 && minute <= 120)
					|| (info == InfoSupplementaire.TIR_AU_BUT)) {
				/* TEST DES MINUTES */
				if (minute == -1
						|| ((butEquipeUne.isEmpty() || minute >= butEquipeUne
								.get(butEquipeUne.size() - 1).getMinute()) && (butEquipeDeux
								.isEmpty() || minute >= butEquipeDeux.get(
								butEquipeDeux.size() - 1).getMinute()))) {
					/* TEST DES EQUIPES */
					if (equipe == 1 && equipeUne.getJoueurs().contains(nom)) {

						But b = new But(nom, minute);
						if (minute == -1) {
							tirsAuButEquipeUne.add(b);
						} else
							butEquipeUne.add(b);
					} else if (equipe == 2
							&& equipeDeux.getJoueurs().contains(nom)) {
						But b = new But(nom, minute);
						if (minute == -1) {
							tirsAuButEquipeDeux.add(b);
						} else
							butEquipeDeux.add(b);
					} else {
						throw new Exception(
								"Pas de correspondance but/joueur/equipe");
					}
				} else
					throw new Exception(
							"Impossible d'ajouter un but avant un autre but");
			} else
				throw new Exception(
						"Impossible d'ajouter un but à cette minute durant cette période");
		} else
			throw new Exception("Impossible de modifier une rencontre terminé");
	}

	/**
	 * Avance les informations de la rencontre
	 */
	public void modifierInfo() {
		if (!termine && arbitre != null) {
			switch (info) {
			case NONE:
				if (butEquipeUne.size() == butEquipeDeux.size())
					info = InfoSupplementaire.PROLONGATION;
				break;
			case PROLONGATION:
				if (butEquipeUne.size() == butEquipeDeux.size())
					info = InfoSupplementaire.TIR_AU_BUT;
				break;
			default:
				// info = InfoSupplementaire.NONE;
			}
		}
	}

	public int infoToInt() {
		switch (info) {
		case NONE:
			return 0;
		case PROLONGATION:
			return 1;
		case TIR_AU_BUT:
			return 2;
		default:
			return 0;
		}
	}

	public boolean aDemarre() {
		return (butEquipeUne.size() > 0 || butEquipeDeux.size() > 0
				|| tirsAuButEquipeUne.size() > 0 || tirsAuButEquipeDeux.size() > 0);
	}
}
